#include <iostream>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <vector>
#include "task.hpp"
#include <ctime>
#include <sys/wait.h>
using namespace std;

enum
{
    UsageError = 1,
    ArgError = 2,
    PipeError = 3
};

void Usage(const string &proc)
{
    cout << "Usage: " << proc << " subprocess-num" << endl;
}
// .processpool 5 表示代表这个进程中有5个进程
class Channel // 用于描述所有的管道.
{
public:
    Channel(int wfd, pid_t sub_id, const std::string &name) : _wfd(wfd),
                                                              _sub_process_id(sub_id),
                                                              _name(name)
    {
    }
    ~Channel() {}
    void PrintDeBug()
    {
        cout << " wfd: " << _wfd;
        cout << " _sub_process_id: " << _sub_process_id;
        cout << " name: " << _name << endl;
    }
    // 用于关闭子进程的读端
    void Close()
    {
        close(_wfd);
    }
    string name(){return _name;}
    int wfd(){return _wfd;}
    pid_t pid(){return _sub_process_id;}
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class ProcessPool
{
public:
    int CreateProcess(work_t work) // 回调函数
    {
        // 创建子进程
        for (int number = 0; number < _sub_process_num; number++)
        {
            vector<int> fds;
            int pipfd[2]{0};
            int n = pipe(pipfd); // n为0就是成功 n为-1就是失败.
            if (n < 0)
                return PipeError;

            pid_t id = fork();   // 创建子进程
            if (id == 0)
            {
                cout<<"close w fd :  ";
                if(!fds.empty())
                {
                    for(int fd: fds)
                    {
                        close(fd); // 修复子进程的wfd全是3的bug
                        cout<< fd;
                    }
                    cout<<endl;
                }
                // child
                close(pipfd[1]); // 关闭写端,关闭1即可.

                // TODO
                dup2(pipfd[0],0); // 输入重定向,从管道中读取数据
                work(pipfd[0]); // 传递读文件描述符
                exit(0);
            }
            sleep(2);
            // father
            string cname = "channel-" + to_string(number);
            close(pipfd[0]); // 关闭读端,关闭0
            channels.push_back(Channel(pipfd[1], id, cname));

            // 让父进程的wfd 保存
            fds.push_back(pipfd[1]);
        }
        return 0;
    }
    int NextChannel()
    {
        static int next = 0;
        int c = next++;
        next=next%(channels.size());
        return c;
    }
    void DebugPrint()
    {
        for (auto &channel : channels)
        {
            channel.PrintDeBug();
        }
    }
    void KillAll()
    {
        for(auto& channel:channels)
        {
            
            channel.Close();
            cout<<"close Done! pid is : "<<channel.pid()<<endl;
        }

    }

    void Wait()
    {
        for(auto& channel :channels)
        {
            pid_t pid = channel.pid();
            cout<<"pid :"<<pid<<endl;
            pid_t rid = waitpid(pid,nullptr,0);
            if(rid == pid)
            {
                cout<<"wait sub process: "<< channel.pid() << "successs.."<<endl;
            }
        }
    }
    void SendTaskCode(int index,uint32_t code)
    {
        cout<<"send code:"<<code<<" to "<<channels[index].name()<<" sub_process:"<<channels[index].pid()<<endl;
        // 进行任务发送
        write(channels[index].wfd(),&code,sizeof(code));
    }
    ProcessPool(int sub_process_num)
        : _sub_process_num(sub_process_num)
    {
    }
    ~ProcessPool() {}
private:
    int _sub_process_num;
    vector<Channel> channels;
};

void CtrlProcessPool(ProcessPool* processpool_ptr,int cnt)
{
    while(cnt)
    {
        // a. 选择一个进程和通道.
        int channel = processpool_ptr->NextChannel();
        cout<<"channel: "<<channel<<endl;
        // b.要选择一个任务,且负载均衡.
        uint32_t command_code = NextTask();
        // c. 发送任务
        processpool_ptr->SendTaskCode(channel,command_code);
        sleep(1);
        cnt--; // 控制任务的个数.
    } 
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        // 此时就说明不会使用这个软件
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num = std::stoi(argv[1]); // 记子l进程的个数
    if (sub_process_num <= 0)
        return ArgError;
    
    srand((uint64_t)time(nullptr)); // 种一个随机数种子

    // 1.创建子进程和通信信道.
    ProcessPool *processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreateProcess(worker); // 创建出指定数量的进程.

    // processpool_ptr->DebugPrint();
    
    // 2.控制子进程
    CtrlProcessPool(processpool_ptr,10);
    cout<<"run Done"<<endl;

    // 3.回收子进程
    processpool_ptr->KillAll();
    // 回收子进程
    processpool_ptr->Wait();


    
    sleep(100);
    delete processpool_ptr;
    return 0;
}
